
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>RabbitMQ死信和延时队列 - 学习卡片</title>
      <style>
        body { font-family: sans-serif; background-color: #f0f8ff; color: #333; display: flex; flex-direction: column; align-items: center; padding: 50px 20px; }
        .header h1 { font-size: 32px; }
        .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; width: 100%; max-width: 1200px; }
        .card-container { perspective: 1200px; cursor: pointer; height: 250px; }
        .card { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 0.7s; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .card-container.flipped .card { transform: rotateY(180deg); }
        .card-face { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; flex-direction: column; box-sizing: border-box; border-radius: 16px; background-color: #fff; padding: 24px; }
        .card-back { background-color: #f0fff4; transform: rotateY(180deg); justify-content: space-between; }
        .card-category { font-size: 14px; color: #0052d9; margin-bottom: 8px; font-weight: 500; }
        .card-question { font-size: 20px; font-weight: 500; flex-grow: 1; display: flex; align-items: center; justify-content: center; text-align: center; }
        .card-answer-wrapper { flex-grow: 1; overflow-y: auto; }
        .card-answer { font-size: 15px; line-height: 1.7; }
        .card-footer { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 16px; margin-top: 16px; }
        .card-source { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>RabbitMQ死信和延时队列 - 学习卡片</h1>
      </div>
      <div class="grid-container">
        
    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">什么是“死信”（Dead Letter）？如果一条消息成为死信但没有为其配置相应的死信队列，它会面临什么结果？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">死信是指因为特定原因导致队列中某些无法被消费的消息。如果RabbitMQ中产生了死信并且配置了死信队列信息，消息将被投递到死信队列中；但如果没有配置，该消息将会被直接丢弃。</div>
          </div>
          <div class="card-source">来源: 什么是死信队列</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">根据文档，有哪三种主要情况会导致一条消息成为死信？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">导致消息成为死信的三种主要情况是：1. 消息被消费者拒绝（通过 basic.reject 或 basic.nack），并且 requeue 参数被设置为 false。2. 消息的TTL（Time-To-Live，存活时间）过期。3. 消息所在的队列达到了最大长度，即队列已满。</div>
          </div>
          <div class="card-source">来源: 死信队列的来源</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">在配置业务队列时，需要设置哪两个关键参数来关联死信交换机和死信路由键？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">在声明业务队列的参数（args）中，需要配置两个关键参数：1. `x-dead-letter-exchange`，用于声明当前队列绑定的死信交换机。2. `x-dead-letter-routing-key`，用于声明当前队列的死信路由键。</div>
          </div>
          <div class="card-source">来源: 配置死信队列</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">RabbitMQ 是如何通过组合现有功能来实现延时队列的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">RabbitMQ 通过结合 TTL（消息或队列的存活时间）机制和死信队列功能来实现延时队列。具体做法是：将消息发送到一个设置了TTL的业务队列，当消息在该队列中存活时间到期后，它会变成“死信”，并被自动路由到预先配置好的死信队列中。消费者只需监听这个死信队列，即可实现延时消费的效果。</div>
          </div>
          <div class="card-source">来源: 延时队列的设置</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">为整个队列设置TTL和为单条消息设置TTL，两者在处理过期消息的方式上有何核心区别？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">核心区别在于消息被丢弃的时机。如果为整个队列设置TTL，一旦消息过期，就会被队列立即丢弃。而如果为单条消息设置TTL，消息即使过期了也不一定被马上丢弃，因为RabbitMQ只在消息即将投递给消费者之前才会判断其是否过期。</div>
          </div>
          <div class="card-source">来源: 给队列设置超时时间</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">消费者消息确认机制中，`autoAck` 参数设置为 `true` 和 `false` 有何根本区别？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">当 `autoAck` 设置为 `true` 时，RabbitMQ 会自动将发送出去的消息标记为确认并从内存或磁盘中删除，无论消费者是否成功处理。而当 `autoAck` 设置为 `false` 时（即手动ack），RabbitMQ会等待消费者显式地回复确认信号后，才将消息移除，这保证了消费者有足够的时间处理消息，防止因进程崩溃导致消息丢失。</div>
          </div>
          <div class="card-source">来源: 消费者消息确认机制</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">当消费者使用 `basic.nack` 或 `basic.reject` 方法拒绝消息时，`requeue` 参数的作用是什么？它如何与死信队列功能联动？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">`requeue` 参数决定了被拒绝的消息是否重新入队。若设置为 `true`，消息会重新存入队列等待下次投递。若设置为 `false`，消息会立即从队列中移除。当 `requeue` 被设置为 `false` 时，如果该队列配置了死信交换机，被拒绝的消息就会被发送到死信队列，从而启用“死信队列”的功能。</div>
          </div>
          <div class="card-source">来源: 消费者消息拒绝</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">场景</div>
          <div class="card-question">文档中描述的导致消息重复消费的典型场景是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">场景</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">典型的场景是：消费者成功消费了消息，但在准备向MQ发送ACK确认时，网络出现闪断导致连接和channel断开。MQ因为没有收到ACK，会认为消息未被成功消费，于是将该消息重新变为待分配状态并投递给下一个（或重连后的同一个）消费者，从而导致同一条消息被消费了两次。</div>
          </div>
          <div class="card-source">来源: 消息的重复消费</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">使用消息队列（MQ）会给系统架构带来哪些主要优点？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">根据文档，使用MQ主要有三大优点：1. 异步：实现任务的异步处理，提高系统响应速度和吞吐量。2. 解耦：降低服务或模块之间的耦合度，使得系统更易于维护和扩展。3. 削峰填谷：应对突发流量高峰，将请求暂存到队列中，由消费者按自身处理能力平稳地处理，防止系统过载。</div>
          </div>
          <div class="card-source">来源: MQ优点和缺点</div>
        </div>
      </div>
    </div>

      </div>
    </body>
    </html>
